package nl.cbnl.ifd;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import jsdai.SIso_12006_3_version_16_draft_proposal.AIfddescription;
import jsdai.SIso_12006_3_version_16_draft_proposal.AIfdlanguage;
import jsdai.SIso_12006_3_version_16_draft_proposal.AIfdname;
import jsdai.SIso_12006_3_version_16_draft_proposal.AIfdphenomenon;
import jsdai.SIso_12006_3_version_16_draft_proposal.AIfdrelspecializes;
import jsdai.SIso_12006_3_version_16_draft_proposal.AIfdsubject;
import jsdai.SIso_12006_3_version_16_draft_proposal.CIfdlanguage;
import jsdai.SIso_12006_3_version_16_draft_proposal.CIfdrelspecializes;
import jsdai.SIso_12006_3_version_16_draft_proposal.CIfdsubject;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfddescription;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfdlanguage;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfdname;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfdphenomenon;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfdrelspecializes;
import jsdai.SIso_12006_3_version_16_draft_proposal.EIfdsubject;
import jsdai.dictionary.AEntity_definition;
import jsdai.dictionary.AExplicit_attribute;
import jsdai.dictionary.EEntity_definition;
import jsdai.dictionary.EExplicit_attribute;
import jsdai.lang.Aggregate;
import jsdai.lang.EEntity;
import jsdai.lang.SdaiException;
import jsdai.lang.SdaiIterator;
import jsdai.lang.SdaiModel;

import org.apache.commons.lang.WordUtils;
import org.coode.owlapi.turtle.TurtleOntologyFormat;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AddImport;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLImportsDeclaration;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.util.AutoIRIMapper;
import org.semanticweb.owlapi.util.DefaultPrefixManager;
import org.semanticweb.owlapi.util.SimpleIRIMapper;

public class IFD_EXPRESS2OWL_simpleOWL {

	private HashMap<EEntity_definition, ArrayList<EExplicit_attribute>>  entities= new HashMap<EEntity_definition,ArrayList<EExplicit_attribute>>();
	private HashMap<EIfdsubject, OWLClass>  clsMap= new HashMap<EIfdsubject, OWLClass>();
	private EIfdlanguage Dutch, English;
	private OWLOntologyManager manager;
	private static String ifdv16="http://www.tno.org/ifdv16#";
	private static String dc="http://purl.org/dc/elements/1.1#";
	public IFD_EXPRESS2OWL_simpleOWL() throws Exception{



		manager = OWLManager.createOWLOntologyManager();
		OWLDataFactory df = manager.getOWLDataFactory();
		//		 File file = new File("ifdv16.ttl");
		//	        // Now load the local copy
		//	     OWLOntology localIfd = manager.loadOntologyFromOntologyDocument(file);
		//	     printOntology(manager,localIfd);
		//	     System.out.println(localIfd.getAxiomCount());
		//	     Iterator<OWLClass> iterator = localIfd.getClassesInSignature().iterator();
		//	     while (iterator.hasNext()) {
		//			OWLClass owlClass = (OWLClass) iterator.next();
		//		//	System.out.println(owlClass.toStringID());
		//			Iterator<OWLAxiom> iterator2 = owlClass.asOWLClass().getReferencingAxioms(localIfd).iterator();
		//			while (iterator2.hasNext()) {
		//				OWLAxiom owlAxiom = (OWLAxiom) iterator2.next();
		//		//		System.out.println("          "+owlAxiom.toString());
		//				
		//			}
		//		}


		// read in the Semantic Concepts Dump from a part 21 file


		STEPLoader stp = new STEPLoader("test.p21");
		SdaiModel smodel = stp.getModel();
		Aggregate instances = smodel.getInstances();
		SdaiIterator instIter = instances.createIterator();
		while (instIter.next()) {
			EEntity ins = (EEntity) instances.getCurrentMemberObject(instIter);
			EEntity_definition definition = ins.getInstanceType();
			if (!entities.containsKey(definition)) {
				ArrayList<EExplicit_attribute> explicit_attrs = new ArrayList<EExplicit_attribute>();

				findAttributes(definition, explicit_attrs);
				entities.put(definition, explicit_attrs);
			}
		}

		instances = smodel.getInstances();
		instIter = instances.createIterator();

		// look for the English and Dutch IfdLanguages to get names later

		AIfdlanguage languages = (AIfdlanguage) smodel.getEntityExtentInstances(CIfdlanguage.class); 
		SdaiIterator it_languages= languages.createIterator(); 
		while (it_languages.next()) {
			EIfdlanguage lang= languages.getCurrentMember(it_languages); 
			String lc = lang.getLanguagecode(null);
			if (lc.equalsIgnoreCase("nl-NL"))
				Dutch = lang;
			else if (lc.equalsIgnoreCase("en-EN"))
				English = lang;


		}




		//			
		//			
		//			while (instIter.next()&&count<maxNodes) {
		//				count++;
		//				EEntity ins = (EEntity)instances.getCurrentMemberObject(instIter);
		//				String type = ins.getInstanceType().getName(null);
		//				System.out.println(type+ " : "+ins.toString());
		//				EEntity_definition def = ins.getInstanceType();
		//				
		//				//AExplicit_attribute attributes = def.getExplicit_attributes(null);
		//				//SdaiIterator i = attributes.createIterator();
		//				ArrayList<EExplicit_attribute> atts = entities.get(ins.getInstanceType());
		//				
		//				if (atts!=null){
		//					Iterator<EExplicit_attribute> attIter = atts.iterator();
		//					while (attIter.hasNext()) {
		//				
		//				
		//			
		//						EExplicit_attribute att = attIter.next();
		//					System.out.println(def.getName(null)+":"+att.getName(null));
		//					}
		//				}
		//			}
		//			
		//			

		// Set up the ontology

		IRI ontologyIRI = IRI.create("http://www.cb-nl.nl/semanticconcepts/def");
		// Create a document IRI which can be resolved to point to where our
		// ontology will be saved.
		//IRI documentIRI = IRI.create("file:/tmp/cbnl.ttl");
		URL currentClassPathUrl = ClassLoader.getSystemResource("");
		String currentProjectPathUrl = currentClassPathUrl+"../";
		IRI documentIRI = IRI.create(currentProjectPathUrl+"/output/cbnl.ttl");
		AutoIRIMapper auto= new AutoIRIMapper(new File(currentProjectPathUrl+"/output/"),false);
		Set<String> exts = new HashSet<String>();
		exts.add("ttl");
		auto.setFileExtensions(exts);

		// Set up a mapping, which maps the ontology to the document IRI
		SimpleIRIMapper mapper = new SimpleIRIMapper(ontologyIRI, documentIRI);
		manager.addIRIMapper(mapper);
		manager.addIRIMapper(auto);
		DefaultPrefixManager pm = new DefaultPrefixManager();



		OWLOntology bsDD = manager.createOntology(ontologyIRI);
		OWLImportsDeclaration importDeclaraton    =   df.getOWLImportsDeclaration(IRI.create("http://www.tno.org/ifdv16#"));
		manager.applyChange(new AddImport(bsDD, df.getOWLImportsDeclaration(IRI.create(ifdv16))));
		pm.setDefaultPrefix("http://www.cb-nl.nl/semanticconcepts/def");
		pm.setPrefix("dc:", "http://purl.org/dc/elements/1.1/");

		//TODO add Dublin core ontology from http://purl.org/dc/elements/1.1/


		//pm.setPrefix("ifd:", "http://www.tno.org/ifdv16#");

		//        importDeclaraton    =   df.getOWLImportsDeclaration(IRI.create("http://purl.org/dc/elements/1.1/description#"));
		//	    manager.applyChange(new AddImport(bsDD, df.getOWLImportsDeclaration(IRI.create(ifdv16))));
		//         pm.setPrefix("dc:", "http://purl.org/dc/elements/1.1#");
		//        

		//http://purl.org/dc/elements/1.1/
		//OWLClass object = df.getOWLClass("ifd:ifdObject", pm);
		//Iterator<OWLAxiom> iterator2 = object.asOWLClass().getReferencingAxioms(bsDD).iterator();
		//while (iterator2.hasNext()) {
		//	OWLAxiom owlAxiom = (OWLAxiom) iterator2.next();		
		//	System.out.println("          "+owlAxiom.toString());
		//}



		int count = 0;
		int maxNodes = 100000;


		AIfdsubject subjects = (AIfdsubject) smodel.getEntityExtentInstances(CIfdsubject.class); 
		SdaiIterator it_products = subjects.createIterator(); 
		while (it_products.next()) {
			EIfdsubject sub = subjects.getCurrentMember(it_products); 
			AIfdname names = sub.getNames(null);

			String enname = getName(names,"en-In");
			if (enname !=null)
			{
				String wordStr = WordUtils.capitalizeFully(enname);
				wordStr= wordStr.replaceAll(" ", "");
				System.out.println("INSTANCE: " +enname + " : " +wordStr);
				OWLClass clsA = df.getOWLClass(IRI.create(ontologyIRI + "#"+wordStr));
				clsMap.put(sub, clsA);
				OWLAnnotation commentAnno = df.getOWLAnnotation(df.getRDFSLabel(),df.getOWLLiteral(enname, "en"));
				OWLAxiom ax = df.getOWLAnnotationAssertionAxiom(clsA.getIRI(), commentAnno);
				manager.addAxiom(bsDD, ax);

				String nlname = getName(names,"nl-NL");
				commentAnno = df.getOWLAnnotation(df.getRDFSLabel(),df.getOWLLiteral(nlname, "nl"));
				ax = df.getOWLAnnotationAssertionAxiom(clsA.getIRI(), commentAnno);
				manager.addAxiom(bsDD, ax);

				// we don't know wether there is a description, so sourround it with a try catch
				try {
					AIfddescription descr= sub.getDescriptions(null);



					String nldescr = getDescription(descr, "nl-NL");
					commentAnno = df.getOWLAnnotation(df.getRDFSComment(),df.getOWLLiteral(nldescr, "nl"));
					ax = df.getOWLAnnotationAssertionAxiom(clsA.getIRI(), commentAnno);
					manager.addAxiom(bsDD, ax);

					String endescr = getDescription(descr, "en-In");
					commentAnno = df.getOWLAnnotation(df.getRDFSComment(),df.getOWLLiteral(endescr, "en"));
					ax = df.getOWLAnnotationAssertionAxiom(clsA.getIRI(), commentAnno);
					manager.addAxiom(bsDD, ax);
				} catch (Exception e) {
					
					System.err.println("no description");
				}

				// TODO add dublin core dc:date to each class
				// find out how meta information could also be added to the individual rdfs:labels etc. Axiom annotations?
				
//									OWLAnnotationProperty dcdate = df.getOWLAnnotationProperty(IRI.create("dc:description"));
//									dcdate.getOWLLiteral(nldescr, "nl");
//										ax = df.getOWLAnnotationAssertionAxiom(clsA.getIRI(), commentAnno);
//										manager.addAxiom(bsDD, ax);
			}



		}

		AIfdrelspecializes specializations = (AIfdrelspecializes) smodel.getEntityExtentInstances(CIfdrelspecializes.class); 
		SdaiIterator it_specializations = specializations.createIterator(); 
		while (it_specializations.next()) {
			EIfdrelspecializes sub = specializations.getCurrentMember(it_specializations); 
			EIfdphenomenon relatingphenomenon = sub.getRelatingphenomenon(null);
			OWLClass superCls = clsMap.get(relatingphenomenon);
			AIfdphenomenon relatedphenomena = sub.getRelatedphenomena(null);
			SdaiIterator it_rels = relatedphenomena.createIterator();
			while (it_rels.next())
			{
				EIfdphenomenon rel = relatedphenomena.getCurrentMember(it_rels);
				OWLClass subCls = clsMap.get(rel);
				if (subCls != null && superCls != null)
				{
					OWLAxiom axiom = df.getOWLSubClassOfAxiom(subCls,superCls);
					// add the axiom to the ontology.
					AddAxiom addAxiom = new AddAxiom(bsDD, axiom);
					// We now use the manager to apply the change
					manager.applyChange(addAxiom);
				}
			}	


		}


		// write out ontology as TTL
		
		TurtleOntologyFormat turtleFormat = new TurtleOntologyFormat();
		turtleFormat.copyPrefixesFrom(pm);
		turtleFormat.setDefaultPrefix(ontologyIRI + "#");
		manager.saveOntology(bsDD,turtleFormat,documentIRI);
	}

	private String getName(AIfdname names, String  lang)  {
		try {
			SdaiIterator it_names = names.createIterator(); 
			while (it_names.next()) {
				EIfdname name = names.getCurrentMember(it_names); 
				if (name.getLanguagename(null).getLanguagecode(null).equalsIgnoreCase(lang))
				{
					return name.getName(null);
				}
			}
		} catch (SdaiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getDescription(AIfddescription descr, String  lang)  {
		try {
			SdaiIterator it_names = descr.createIterator(); 
			while (it_names.next()) {
				EIfddescription desc = descr.getCurrentMember(it_names); 
				if (desc.getLanguagename(null).getLanguagecode(null).equalsIgnoreCase(lang))
				{
					return desc.getDescription(null);
				}
			}
		} catch (SdaiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private static void printOntology(OWLOntologyManager manager, OWLOntology ontology) {
		IRI ontologyIRI = ontology.getOntologyID().getOntologyIRI();
		IRI documentIRI = manager.getOntologyDocumentIRI(ontology);
		System.out.println(ontologyIRI == null ? "anonymous" : ontologyIRI
				.toQuotedString());
		System.out.println("    from " + documentIRI.toQuotedString());
	}

	/* some shortcut routines , not really necessary here, taken from another 
	 * project, where late-bindings where used. 
	 */
	public  void findAttributes(EEntity_definition entity, ArrayList<EExplicit_attribute> attribs) throws SdaiException {
		AEntity_definition supertypes = entity.getSupertypes(null);
		SdaiIterator i = supertypes.createIterator();
		while (i.next()) {
			EEntity_definition superEnt = supertypes.getCurrentMember(i);
			System.out.println("supertype: "+superEnt.getName(null));
			if (!entities.containsKey(superEnt))
			{
				findAttributes(supertypes.getCurrentMember(i), null);
			}
		}

		AExplicit_attribute attributes = entity.getExplicit_attributes(null);
		i = attributes.createIterator();
		while (i.next()) {
			if (attribs==null)
				attribs=new ArrayList<EExplicit_attribute>();
				if (!attribs.contains(attributes.getCurrentMember(i))) { // To avoid dublication of attributes for multiple inheritance with the same root.
					attribs.add(attributes.getCurrentMember(i));

				}
		}
		entities.put(entity, attribs);
	}
}
